package com.sgy.netty.handler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sgy.netty.route.MsgRoute;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.util.CharsetUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class MyMatchingHandler extends SimpleChannelInboundHandler<Object> {
    private static Logger log = LoggerFactory.getLogger(MyMatchingHandler.class);

    private WebSocketServerHandshaker handshaker;

    @Autowired
    private MsgRoute msgRoute;

    private static ExecutorService threadPool = Executors.newCachedThreadPool();


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        //传统http接入
        if(msg instanceof FullHttpRequest){
            handleHttpRequest(ctx,(FullHttpRequest)msg);
        }
        //websocket接入
        if(msg instanceof WebSocketFrame){
            handleWebSocketFrame(ctx,(WebSocketFrame) msg);
        }
    }

    /**
     * 处理http请求，完成websocket握手
     * @param ctx
     * @param request
     */
    private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest request){
        //如果Http解码失败，返回http异常
        if(!request.getDecoderResult().isSuccess() || (!"websocket".equals(request.headers().get("Upgrade")))){
            sendHttpResponse(ctx,request,new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
            return;
        }

        //正常websocket的http连接请求，构造握手响应返回
        WebSocketServerHandshakerFactory wsFactory=new WebSocketServerHandshakerFactory("ws://"+request.headers().get(HttpHeaders.Names.HOST),null,false);
        handshaker = wsFactory.newHandshaker(request);
        if(handshaker == null){ //无法处理的websocket版本
            WebSocketServerHandshakerFactory.sendUnsupportedWebSocketVersionResponse(ctx.channel());
        }else { //向客户端发送websocket握手，完成握手
            handshaker.handshake(ctx.channel(),request);
            //记录管道处理上下文，便于服务器推送数据到客户端
        }
    }
    /**
     * http返回
     * @param ctx
     * @param request
     * @param response
     */
    private static void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest request, FullHttpResponse response){
        //响应客户端
        if(response.getStatus().code()!=200){
            ByteBuf buf = Unpooled.copiedBuffer(response.getStatus().toString(), CharsetUtil.UTF_8);
            response.content().writeBytes(buf);
            buf.release();
            HttpHeaders.setContentLength(response,response.content().readableBytes());
        }

        //如果是非keep-alive,关闭连接
        ChannelFuture future = ctx.channel().writeAndFlush(response);
        if(!HttpHeaders.isKeepAlive(request) || response.getStatus().code()!=200){
            future.addListener(ChannelFutureListener.CLOSE);
        }
    }

    private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
        log.debug("handleWebSocketFrame:"+Thread.currentThread().getName());
        // 判断是否是关闭链路的指令

        if (frame instanceof CloseWebSocketFrame) {
            handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
            return;
        }
        // 判断是否是Ping消息
        if (frame instanceof PingWebSocketFrame) {
            ctx.channel().write(new PongWebSocketFrame(frame.content().retain()));
            return;
        }
        // 本例程仅支持文本消息，不支持二进制消息
        if (!(frame instanceof TextWebSocketFrame)) {
            throw new UnsupportedOperationException(
                    String.format("%s frame types not supported", frame.getClass().getName()));
        }

        // 返回应答消息
        String message = ((TextWebSocketFrame) frame).text();
        JSONObject json = JSON.parseObject(message);
        int type = json.getInteger("type");
        Channel channel = ctx.channel();
        switch (type){
            case 9:
                boolean isSuccess = UserInfoManager.saveUser(channel, json.getString("username"), json.getString("password"));
                if(!isSuccess){
                    UserInfoManager.addChannel(channel,json.getString("username"));
                }
            case 2:
                UserInfoManager.p2p(json.getString("username"),json.getString("reciver"),json.getString("mess"));
        }



//        log.info(String.format("%s received %s", ctx.channel(), request));
//
//        if(StringUtils.isNotEmpty(request)){
//            WorkRunable workRunable = new WorkRunable(ctx,request);
//            threadPool.execute(workRunable);
//        }

    }


    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("与客户端建立连接，通道开启"+Thread.currentThread().getName());
    }

    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info("与客户端断开连接，通道销毁"+Thread.currentThread().getName());
    }


    class WorkRunable implements Runnable{

        private ChannelHandlerContext ctx;
        private String request;

        public WorkRunable(ChannelHandlerContext ctx,String request){
            this.ctx=ctx;
            this.request=request;
        }
        @Override
        public void run() {
            msgRoute.distribute(ctx,request);
        }
    }
}
